package com.taijia.chapter9;

import com.alibaba.fastjson.JSON;

/**
 * 生产者消费者.
 * User: taijia
 * Date: 2015/3/15
 * Time: 19:36
 * To change this template use File | Settings | File Templates.
 */
public class ProducerConsumer {
    public static void main(String[] args) {
        SyncTack st = new SyncTack();
        new Thread(new Producer(st)).start();
        new Thread(new Consumer(st)).start();
    }
}

/**
 * 窝头
 */
class WoTou {
    int id;

    WoTou(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "WoTou : " + id;
    }
}

/**
 * 篮子
 */
class SyncTack {
    int index = 0;
    WoTou[] arrWT = new WoTou[6];

    public synchronized void push(WoTou wt) {
        while (index == arrWT.length) {
            // 一般都while 防止if穿透
            // 也就是即使异常了，回头还是要检查是否进入阻塞状态
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.notify();
        arrWT[index] = wt;
        index++;
    }

    public synchronized WoTou pop() {
        while (index == 0) {
            try {
                // 锁定在当前对象上的线程暂停，wait的外围方法必须是synchronized
                // wait后对象的锁释放，wait还需叫醒(notify)
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.notify();
        index--;
        return arrWT[index];
    }
}

/**
 * 生产者
 */
class Producer implements Runnable {
    SyncTack st;

    Producer(SyncTack st) {
        this.st = st;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            WoTou wt = new WoTou(i);
            st.push(wt);
            System.out.println("produce: " + wt);
            System.out.println("produce: " + JSON.toJSONString(st.arrWT));
            try {
                Thread.sleep((long) (Math.random()*1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

/**
 * 消费者
 */
class Consumer implements Runnable {
    SyncTack st;

    Consumer(SyncTack st) {
        this.st = st;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("consume: " + st.pop());
            System.out.println("consume: " + JSON.toJSONString(st.arrWT));
            try {
                Thread.sleep((long) (Math.random()*1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}